﻿using Serilog;
using System;
using System.Net.Sockets;
using System.Text;

namespace MoonFramework.Net
{
    public class SocketReceiver
    {
        public delegate void DataReceivedEventHandler(byte[] data);
        public delegate void DisconnectedEventHandler();

        // 成功收到消息的委托事件
        public event DataReceivedEventHandler DataReceived;
        // 连接断开的委托事件
        public event DisconnectedEventHandler Disconnected;

        // 缓冲区
        private byte[] mBuffer;
        // 每次读取的开始位置
        private int mStartIndex = 0;

        private Socket mSocket;
        private SocketAsyncEventArgs mReceiveEventArgs;

        public SocketReceiver(Socket socket) : this(socket, 1024 * 64)
        { }

        public SocketReceiver(Socket socket, int bufferSize)
        {
            this.mSocket = socket;
            mBuffer = new byte[bufferSize];
            mReceiveEventArgs = new SocketAsyncEventArgs();
            mReceiveEventArgs.SetBuffer(mBuffer, 0, mBuffer.Length);
            mReceiveEventArgs.Completed += OnReceiveCompleted;
        }

        public void Start()
        {
            ReceiveAsync();
        }

        private void ReceiveAsync()
        {
            bool willRaiseEvent = mSocket.ReceiveAsync(mReceiveEventArgs);
            if (!willRaiseEvent)
            {
                ProcessReceive(mReceiveEventArgs);
            }
        }

        private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
        {
            ProcessReceive(e);
        }

        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            try
            {
                if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
                {
                    HandleDisconnection();
                    return;
                }

                int bytesRead = e.BytesTransferred;
                int totalBytes = mStartIndex + bytesRead;
                int currentOffset = 0;

                while (totalBytes - currentOffset >= 4)
                {
                    int messageLength =GetInt32BE(mBuffer, currentOffset);

                    if (totalBytes - currentOffset < messageLength + 4)
                        break;
                    int messageStartIndex = currentOffset + 4;
                    byte[] messageData = new byte[messageLength];
                    Array.Copy(mBuffer, messageStartIndex, messageData, 0, messageLength);
                    DataReceived?.Invoke(messageData);

                    currentOffset += 4 + messageLength;
                }

                mStartIndex = totalBytes - currentOffset;
                if (mStartIndex > 0)
                {
                    Array.Copy(mBuffer, currentOffset, mBuffer, 0, mStartIndex);
                }

                ReceiveAsync();
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        private void HandleDisconnection()
        {
            try
            {
                Disconnected?.Invoke();
                mSocket.Shutdown(SocketShutdown.Both);
            }
            catch { } // throws if client process has already closed
            mSocket.Close();
            mSocket = null;
        }

        private void HandleException(Exception ex)
        {
            Log.Warning("异常发生: {0}", ex.Message);
            HandleDisconnection();
        }

        private int GetInt32BE(byte[] data, int index)
        {
            return (data[index] << 24) | (data[index + 1] << 16) | (data[index + 2] << 8) | data[index + 3];
        }
    }
}
